﻿namespace Sgr.Workspace.Models
{
    public class DailyActivityOverviewInfo
    {
        #region 常量定义

        private const int ARRAY_SIZE = 30;

        #endregion 常量定义

        #region 数据存储

        /// <summary>
        /// 近三十天，每天日活用户数
        /// </summary>
        public int[] Activities { get; set; } = new int[ARRAY_SIZE];

        #endregion 数据存储

        #region 核心方法

        /// <summary>
        /// 根据日期获取数组下标索引
        /// </summary>
        /// <param name="dateTime">目标日期</param>
        /// <returns>数组索引 (0-29)</returns>
        private static int GetIndex(DateTime dateTime)
        {
            int daysDiff = (dateTime.Date - Constant.UnixEpoch.Date).Days;
            return Math.Abs(daysDiff % ARRAY_SIZE);
        }

        /// <summary>
        /// 更新指定日期的数据
        /// </summary>
        /// <param name="dateTime">日期</param>
        /// <param name="total">操作总数</param>
        public void UpdateData(DateTime dateTime, int total)
        {
            if (total < 0)
                total = 0;

            int index = GetIndex(dateTime);
            Activities[index] = total;
        }

        ///// <summary>
        ///// 获取指定天数范围的统计数据
        ///// </summary>
        ///// <param name="array">要统计的数组</param>
        ///// <param name="daysBack">从今天往前的天数</param>
        ///// <param name="count">统计的天数</param>
        ///// <returns>统计结果</returns>
        //private int GetRangeSum(int[] array, int daysBack, int count)
        //{
        //    if (daysBack < 0 || count <= 0 || daysBack + count > ARRAY_SIZE)
        //        return 0;

        //    var today = DateTime.UtcNow.Date;
        //    int startIndex = GetIndex(today);
        //    int sum = 0;

        //    for (int i = daysBack; i < daysBack + count; i++)
        //    {
        //        int index = (startIndex - i - 1 + ARRAY_SIZE) % ARRAY_SIZE;
        //        sum += array[index];
        //    }

        //    return sum;
        //}

        #endregion 核心方法

        /// <summary>
        /// 获取指定天数的日活数组
        /// </summary>
        /// <param name="days">天数（最多30天）</param>
        /// <returns>指定天数的日活用户数数组，索引0为最近的一天</returns>
        public int[] GetActivitiesArray(int days = 7)
        {
            if (days <= 0 || days > ARRAY_SIZE)
                days = 7;

            var today = DateTime.UtcNow.Date;
            int startIndex = GetIndex(today);
            int[] activitiesArray = new int[days];

            for (int i = 0; i < days; i++)
            {
                int index = (startIndex - i - 1 + ARRAY_SIZE) % ARRAY_SIZE;
                activitiesArray[i] = Activities[index];
            }

            return activitiesArray;
        }

        /// <summary>
        /// 计算日活环比增长率（相对于前一天）
        /// </summary>
        /// <returns>环比增长率百分比，正数表示增长，负数表示下降</returns>
        public double GetDailyGrowthRate()
        {
            var recentDays = GetActivitiesArray(2);
            if (recentDays.Length < 2) return 0;

            int today = recentDays[0];     // 最近一天
            int yesterday = recentDays[1]; // 前一天

            if (yesterday == 0)
                return today > 0 ? 100.0 : 0.0;

            return Math.Round((double)(today - yesterday) / yesterday * 100.0, 2);
        }

        /// <summary>
        /// 计算近7天相对于前7天的增长率
        /// </summary>
        /// <returns>周环比增长率百分比</returns>
        public double GetWeeklyGrowthRate()
        {
            var activities = GetActivitiesArray(14);
            if (activities.Length < 14) return 0;

            // 近7天平均值
            double recentWeekAvg = activities.Take(7).Average();
            // 前7天平均值
            double previousWeekAvg = activities.Skip(7).Take(7).Average();

            if (previousWeekAvg == 0)
                return recentWeekAvg > 0 ? 100.0 : 0.0;

            return Math.Round((recentWeekAvg - previousWeekAvg) / previousWeekAvg * 100.0, 2);
        }

        /// <summary>
        /// 计算日活波动性（标准差）
        /// </summary>
        /// <param name="days">分析天数，默认7天</param>
        /// <returns>日活数据的标准差，值越大表示波动越大</returns>
        public double GetVolatility(int days = 7)
        {
            var activities = GetActivitiesArray(days);
            if (activities.Length < 2) return 0;

            double average = activities.Average();
            double sumOfSquares = activities.Sum(x => Math.Pow(x - average, 2));
            return Math.Round(Math.Sqrt(sumOfSquares / activities.Length), 2);
        }

        /// <summary>
        /// 获取日活峰值和谷值
        /// </summary>
        /// <param name="days">分析天数，默认30天</param>
        /// <returns>包含最大值、最小值、最大值日期偏移、最小值日期偏移的元组</returns>
        public (int Max, int Min, int MaxDayOffset, int MinDayOffset) GetPeakAndValley(int days = 30)
        {
            var activities = GetActivitiesArray(days);
            if (activities.Length == 0) return (0, 0, 0, 0);

            int max = activities.Max();
            int min = activities.Min();
            int maxIndex = Array.IndexOf(activities, max);
            int minIndex = Array.IndexOf(activities, min);

            return (max, min, maxIndex, minIndex);
        }

        /// <summary>
        /// 获取连续增长或下降天数
        /// </summary>
        /// <returns>连续天数，正数表示连续增长天数，负数表示连续下降天数，0表示无明显趋势</returns>
        public int GetConsecutiveTrendDays()
        {
            var activities = GetActivitiesArray(ARRAY_SIZE);
            if (activities.Length < 2) return 0;

            int consecutiveDays = 0;
            bool isGrowing = activities[0] > activities[1];

            for (int i = 1; i < activities.Length; i++)
            {
                bool currentGrowing = activities[i - 1] > activities[i];

                if (currentGrowing == isGrowing)
                {
                    consecutiveDays++;
                }
                else
                {
                    break;
                }
            }

            return isGrowing ? consecutiveDays : -consecutiveDays;
        }

        /// <summary>
        /// 获取近7天的日活数组
        /// </summary>
        /// <returns>近7天每日的活跃用户数数组，索引0为最近的一天</returns>
        public int[] GetWeeklyActivitiesArray()
        {
            return GetActivitiesArray(7);
        }

        /// <summary>
        /// 获取近7天日活用户平均数
        /// </summary>
        /// <returns>近7天的日活用户平均数</returns>
        public double GetWeeklyAverageActivities()
        {
            int[] weeklyArray = GetWeeklyActivitiesArray();
            if (weeklyArray.Length == 0) return 0;
            return Math.Round(weeklyArray.Average(), 2);
        }
    }
}